import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt

img = cv.imread('../pic/coin.png')
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 0是手动设置的阈值。因为使用了Otsu's方法，实际的阈值会自动计算，所以这里设置为0
# THRESH_BINARY_INV 意味着大于阈值的像素将被设置为0，小于阈值的像素将被设置为最大值（255）
ret, thresh = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)

# 噪声去除
kernel = np.ones((3, 3), np.uint8)
opening = cv.morphologyEx(thresh, cv.MORPH_OPEN, kernel, iterations=2)
# 再膨胀 使得前景对象更大 进一步扩展前景区域
sure_bg = cv.dilate(opening, kernel, iterations=3)
# 寻找前景区域 找每个非零像素到最近的零像素的距离
dist_transform = cv.distanceTransform(opening, cv.DIST_L2, 5)
# 对距离变换结果进行阈值处理，保留距离大于最大距离0.7倍的区域，这些区域可以认为是前景对象
ret, sure_fg = cv.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0)
# 找到未知区域 从背景区域中减去前景区域，得到未知区域，即那些无法确定是前景还是背景的区域
sure_fg = np.uint8(sure_fg)
unknown = cv.subtract(sure_bg, sure_fg)

# 类别标记 将图像中相连的前景像素分配给不同的标签
ret, markers = cv.connectedComponents(sure_fg)
# 标签的范围是[0, num_labels-1] 为所有的标记加1，保证背景是1而不是0 标签的范围变为[1, num_labels]
markers = markers + 1
# 未知区域的像素值为255 将markers图像中对应于unknown图像中像素值为255的区域设为0,即标记未知区域为0
markers[unknown == 255] = 0
markers = cv.watershed(img, markers)
# -1：表示分水岭边界 将边缘赋值为蓝色
img[markers == -1] = [255, 0, 0]

cv.imshow("org", img)
cv.imshow("thresh", thresh)
cv.imshow("opening", opening)
cv.imshow("sure_bg", sure_bg)
cv.imshow("sure_fg", sure_fg)
cv.imshow("unknown", unknown)
cv.imshow("markers", markers)

cv.waitKey()
cv.destroyAllWindows()
